﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;

namespace OnlineCourse.JWTAuthorizePolicy
{
    public static class JwtBearerExtension
    {

        /// <summary>
        /// 注入jwt策略，在业务API应用中的Startup的ConfigureServices调用
        /// </summary>
        /// <param name="services">IServiceCollection</param>
        /// <param name="issuer">发行人</param>
        /// <param name="audience">订阅人</param>
        /// <param name="secret">密钥</param>
        /// <param name="defaultScheme">默认架构</param>
        /// <param name="policyName">自定义策略名称</param>
        /// <param name="deniedUrl">拒绝路由</param>
        /// <param name="isHttps">是否https</param>
        /// <returns></returns>
        public static AuthenticationBuilder AddPolicyJwtBearer(this IServiceCollection services, string issuer, string audience, string secret, string defaultScheme, string policyName, string deniedUrl, bool isHttps = false)
        {
          
            var keyByteArray = Encoding.ASCII.GetBytes(secret);//获取秘钥编码组
            var signingKey = new SymmetricSecurityKey(keyByteArray);//签名秘钥，以便确定是本人发出的
            var tokenValidationParameters = new TokenValidationParameters//令牌验证参数
            {
                ValidateIssuerSigningKey = true,//验证发行者签名的秘钥
                IssuerSigningKey = signingKey,//发行者签名的秘钥
                ValidateIssuer = true,//验证发行者
                ValidIssuer = issuer,//发行人
                ValidateAudience = true,//验证用户
                ValidAudience = audience,//订阅人
                ValidateLifetime = true,//验证生命周期
                ClockSkew = TimeSpan.Zero,//时钟扭曲，值越小越好
                RequireExpirationTime = true,//过期时间

            };
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);//获取签名证书，用哈希256计算
            //如果第三个参数，是ClaimTypes.Role，上面集合的每个元素的Name为角色名称，如果ClaimTypes.Name，即上面集合的每个元素的Name为用户名
            var permissionRequirement = new PermissionRequirement(
               deniedUrl,//拒绝路由
                ClaimTypes.Role,
                issuer,//发行人
                audience,//订阅人
                signingCredentials,//签名证书
                expiration: TimeSpan.FromHours(168)
                );
            //注入授权Handler
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            services.AddSingleton(permissionRequirement);
            return services.AddAuthorization(options =>
            {
                options.AddPolicy(policyName,
                          policy => policy.Requirements.Add(permissionRequirement));

            })
         .AddAuthentication(options =>
         {
             options.DefaultScheme = defaultScheme;
         })
         .AddJwtBearer(defaultScheme, o =>
         {
             //不使用https
             o.RequireHttpsMetadata = isHttps;
             o.TokenValidationParameters = tokenValidationParameters;
         });
        }
        /// <summary>
        /// 注放Token生成器参数，在token生成项目的Startup的ConfigureServices中使用
        /// </summary>
        /// <param name="services">IServiceCollection</param>
        /// <param name="issuer">发行人</param>
        /// <param name="audience">订阅人</param>
        /// <param name="secret">密钥</param>
        /// <param name="deniedUrl">拒绝路由</param>
        /// <returns></returns>
        public static IServiceCollection AddJTokenBuild(this IServiceCollection services, string issuer, string audience, string secret, string deniedUrl)
        {
            var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret)), SecurityAlgorithms.HmacSha256);
            //如果第三个参数，是ClaimTypes.Role，上面集合的每个元素的Name为角色名称，如果ClaimTypes.Name，即上面集合的每个元素的Name为用户名
            var permissionRequirement = new PermissionRequirement(
               deniedUrl,
                ClaimTypes.Role,
                issuer,
                audience,
                signingCredentials,
                expiration: TimeSpan.FromHours(10)
                );
            return services.AddSingleton(permissionRequirement);

        }
    }
}
